package com.laxcen.facestaticcheck;

import androidx.appcompat.app.AppCompatActivity;

import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.laxcen.facestaticcheck.camera.CameraCallback;
import com.laxcen.facestaticcheck.camera.CameraManager;
import com.laxcen.facestaticcheck.engine.FaceCheckEngine;
import com.laxcen.facestaticcheck.util.MyLogger;
import com.laxcen.facestaticcheck.util.PermissionUtils;
import com.laxcen.facestaticcheck.view.CircleImageView;
import com.laxcen.facestaticcheck.view.RoundFrameLayout;
import com.laxcen.facestaticcheck.view.RoundTextureView;

import java.util.List;

/**
 *   非配合性活体检测
 *   根据摩尔纹 光线 等综合因素判断是否是活体
 *
 */
public class MainActivity extends AppCompatActivity implements
        View.OnClickListener {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_main);
        toCheckPermission();
    }

    private void toCheckPermission(){
        PermissionUtils.checkPermission(this, () -> init());
    }
    @Override
    public void onRequestPermissionsResult(final int requestCode, final String[] permissions, final int[] grantResults) {
        if (requestCode == 1) {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                init();
            } else {
                toCheckPermission();
            }
        }
    }
    //初始化
    private void init() {
        initView();
        initCamera();
        initFaceCheck();
    }





    /*****操作按钮****/
    private ImageView btn_back;//返回
    private TextView pre_toast_text;//提示信息
    private CircleImageView detect_reg_image_item;//通过活体检测
    private Button by_living_detection_btn;//重新检测
    private CircleImageView quality_detect_reg_image_item;//未通过活体检测
    private Button quality_retest_detectBtn;//重新检测
    private TextView no_detectTv;//识别失败的提示信息

    private RelativeLayout pay_hintRl;
    private View finance_quality_test_failed;
    private View finance_by_living_detection;;
    private void initView(){
        btn_back = findViewById(R.id.btn_back);
        pre_toast_text = findViewById(R.id.pre_toast_text);
        detect_reg_image_item = findViewById(R.id.detect_reg_image_item);
        by_living_detection_btn = findViewById(R.id.by_living_detection_btn);
        quality_detect_reg_image_item = findViewById(R.id.quality_detect_reg_image_item);
        quality_retest_detectBtn = findViewById(R.id.quality_retest_detectBtn);
        pay_hintRl = findViewById(R.id.pay_hintRl);
        finance_quality_test_failed = findViewById(R.id.finance_quality_test_failed);
        finance_by_living_detection = findViewById(R.id.finance_by_living_detection);
        no_detectTv = findViewById(R.id.no_detectTv);
        btn_back.setOnClickListener(this);
        by_living_detection_btn.setOnClickListener(this);
        quality_retest_detectBtn.setOnClickListener(this);
        textureView = findViewById(R.id.texture_preview);
        textureView.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener);
    }






    private RoundTextureView textureView;
    private RoundFrameLayout insertFrameLayout;
    private ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener(){
        @Override
        public void onGlobalLayout() {
            textureView.getViewTreeObserver().removeOnGlobalLayoutListener(globalLayoutListener);
            ViewGroup.LayoutParams layoutParams = textureView.getLayoutParams();
            int sideLength = Math.min(textureView.getWidth(), textureView.getHeight()) * 3 / 4;
            layoutParams.width = sideLength;
            layoutParams.height = sideLength;
            textureView.setLayoutParams(layoutParams);
            textureView.turnRound();
            initCamera();
        }
    };

    /**
     * 相机部分
     */
    // 相机的数据 nv21格式
    private static final String TAG = "CameraActicity";
    // 照相机预览宽
    public int previewWidth = 0;
    // 照相机预览高
    public int previewHeight = 0;
    // 展示区域宽
    public static float ScreenWidth;
    // 展示区域高
    public static float ScreenHeight;
    public static int CameraId = 0;
    private boolean isProcessingFrame = false;
    protected byte[] mNV21Bytes;
    private CameraManager cameraManager;
    private Camera.Size previewSize;
    private void initCamera(){
        cameraManager =  new CameraManager.Builder()
                .cameraListener(new CameraCallback() {
                    @Override
                    public void onCameraOpened(Camera camera, int cameraId,
                                               int displayOrientation, boolean isMirror) {
                        previewSize = camera.getParameters().getPreviewSize();
                        //在相机打开时，添加右上角的view用于显示原始数据和预览数据
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //将预览控件和预览尺寸比例保持一致，避免拉伸
                                {
                                    FrameLayout.LayoutParams textureViewLayoutParams = (FrameLayout.LayoutParams) textureView.getLayoutParams();
                                    int newHeight = 0;
                                    int newWidth = textureViewLayoutParams.width;
                                    //横屏
                                    if (displayOrientation % 180 == 0) {
                                        newHeight = textureViewLayoutParams.width * previewSize.height / previewSize.width;
                                    }
                                    //竖屏
                                    else {
                                        newHeight = textureViewLayoutParams.width * previewSize.width / previewSize.height;
                                    }
                                    //当不是正方形预览的情况下，添加一层ViewGroup限制View的显示区域
                                    if (newHeight != textureViewLayoutParams.height) {
                                        insertFrameLayout = new RoundFrameLayout(MainActivity.this);
                                        int sideLength = Math.min(newWidth, newHeight);
                                        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(sideLength, sideLength);
                                        layoutParams.gravity= Gravity.CENTER;
                                        insertFrameLayout.setLayoutParams(layoutParams);
                                        FrameLayout parentView = (FrameLayout) textureView.getParent();
                                        parentView.removeView(textureView);
                                        parentView.addView(insertFrameLayout);

                                        insertFrameLayout.addView(textureView);
                                        FrameLayout.LayoutParams newTextureViewLayoutParams = new FrameLayout.LayoutParams(newWidth, newHeight);
                                        //横屏
                                        if (displayOrientation % 180 == 0) {
                                            newTextureViewLayoutParams.leftMargin = ((newHeight - newWidth) / 2);
                                        }
                                        //竖屏
                                        else {
                                            newTextureViewLayoutParams.topMargin = -(newHeight - newWidth) / 2;
                                        }
                                        textureView.setLayoutParams(newTextureViewLayoutParams);

                                        //把显示宽高传过去方便计算区域
                                        FaceCheckEngine.getInstance(MainActivity.this).setWidthAndHeight(newTextureViewLayoutParams.width,newTextureViewLayoutParams.height);

                                        insertFrameLayout.post(new Runnable() {
                                            @Override
                                            public void run() {
                                                insertFrameLayout.setRadius(100 * Math.min(insertFrameLayout.getWidth(), insertFrameLayout.getHeight()) / 2 / 100);
                                                insertFrameLayout.turnRound();
                                            }
                                        });
                                    }
                                }
                            }
                        });
                    }

                    @Override
                    public void onPreview(byte[] bytes, Camera camera) {
                        if (isProcessingFrame) {
                            return;
                        }
                        isProcessingFrame = true;
                        try {
                            if (mNV21Bytes == null) {
                                Camera.Size previewSize = camera.getParameters().getPreviewSize();
                                previewHeight = previewSize.height;
                                previewWidth = previewSize.width;
                                faceinit();
                            }
                        } catch (final Exception e) {
                            MyLogger.logError(TAG, "onPreviewFrame: " + e);
                            return;
                        }
                        imageConverter = () -> mNV21Bytes = bytes;
                        postInferenceCallback = () -> {
                            camera.addCallbackBuffer(bytes);
                            isProcessingFrame = false;
                        };
                        processImage();
                    }

                    @Override
                    public void onCameraClosed() {
                        onFail("相机已关闭");
                    }

                    @Override
                    public void onCameraError(Exception e) {
                        e.printStackTrace();
                        onFail("打开相机出错:"+e.getMessage());
                    }

                    @Override
                    public void onCameraConfigurationChanged(int cameraID, int displayOrientation) {

                    }
                })
                .specificCameraId(Const.IS_FRONT_CAMERA?1:0)
                .previewOn(textureView)
                .previewSize(new Point(Const.CAMERA_WIDTH, Const.CAMERA_HEIGHT))
                //.rotation(getWindowManager().getDefaultDisplay().getRotation())
                //烟草柜生原本是倒立的，先写死
                .rotation(270)
                .isMirror(Const.IS_MIRROR_DISPLAY)
                .build();
        cameraManager.start();
    }



    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_back:
                finish();
                break;
            case R.id.by_living_detection_btn:
            case R.id.quality_retest_detectBtn:
                pay_hintRl.setVisibility(View.GONE);
                finance_by_living_detection.setVisibility(View.GONE);
                finance_quality_test_failed.setVisibility(View.GONE);
                if(faceCheckEngine!=null){
                    faceCheckEngine.onStartCheck();
                }
                break;
        }
    }

    public void faceinit() {
        mNV21Bytes = new byte[previewHeight * previewWidth];
    }




    protected void processImage() {
        getCameraBytes();
        /**
         *  检测活体
         */
        runInBackground(() -> {
                boolean isShow = pay_hintRl.getVisibility() == View.GONE;
                faceCheckEngine.onLiveFaceCheck(mNV21Bytes,previewWidth,previewHeight,isShow);
        });

        runInBackground(() -> {
            readyForNextImage();
        });
    }

    private Runnable postInferenceCallback;
    private Runnable imageConverter;
    //得到最新的bytes
    protected void getCameraBytes() {
        if (imageConverter != null) {
            imageConverter.run();
        }
    }
    protected void readyForNextImage() {
        if (postInferenceCallback != null) {
            postInferenceCallback.run();
        }
    }

    private Handler handler;
    private HandlerThread handlerThread;
    protected synchronized void runInBackground(final Runnable r) {
        if (handler != null) {
            handler.post(r);
        }
    }


    @Override
    public synchronized void onResume() {
        super.onResume();
        if (cameraManager != null) {
            cameraManager.start();
        }
        handlerThread = new HandlerThread("inference");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
        processImage();
    }
    @Override
    public synchronized void onPause() {
        handlerThread.quitSafely();
        try {
            handlerThread.join();
            handlerThread = null;
            handler = null;
        } catch (final InterruptedException e) {
            MyLogger.logError(TAG, "onPause: " + e);
        }
        if (cameraManager != null) {
            cameraManager.stop();
        }
        super.onPause();
    }

    @Override
    public synchronized void onDestroy() {
        super.onDestroy();
        /**
         * 释放
         * */
        faceCheckEngine.destory();
    }


    /**
     * 输出调试数据
     */
    private TextView mLog;
    private String[] logs = new String[8];
    private void initDebug(){
        mLog = findViewById(R.id.log);
        faceCheckEngine.setOnLogListener((type, log) -> {
            if(!Const.DEBUG){
                return;
            }
            logs[type] = log;
            logs[6] = "适配的相机像素:width["+previewWidth+" px],height["+previewHeight+"px]";
            List<Camera.Size> cameraSizes = cameraManager.getSupportedPreviewSizes();
            String si = "";
            for(Camera.Size size:cameraSizes){
                si+=size.width+" x "+size.height+"\n";
            }
            logs[7]="相机内置照片尺寸:\n"+si;
            runOnUiThread(() -> {
                String log1 = "";
                for(String l:logs){
                    if(!TextUtils.isEmpty(l)){
                        log1 +=l+"\n";
                    }
                }
                mLog.setText(log1);
            });
        });
    }

    //活体检测主程序
    private FaceCheckEngine faceCheckEngine;
    private void initFaceCheck(){
        faceCheckEngine = FaceCheckEngine.getInstance(this);
        initDebug();

        /**
         * 识别结果处理
         */
        faceCheckEngine.setOnFaceCheckResult((type, bitmap) -> {
            switch (type) {
                case Const.ACTION_TYPE_NO_FACE:
                    pre_toast_text.setText("保持面部在取景框内");
                    break;
                case Const.ACTION_TYPE_NOT_LIVE_FACE:
                    faceCheckEngine.onStopCheck();
                    MainActivity.this.onFail("未通过活体检测");
                    break;
                case Const.ACTION_TYPE_LIVE_FACE:
                    faceCheckEngine.onStopCheck();
                    onSuccess(bitmap);
                    break;
                case Const.ACTION_TYPE_TIME_OUT:
                    faceCheckEngine.onStopCheck();
                    MainActivity.this.onFail("识别超时");
                    break;
                case Const.ACTION_TYPE_WAIT_TIME_OUT:
                    faceCheckEngine.onStopCheck();
                    MainActivity.this.onFail("等待检测超时");
                    break;
                case Const.ACTION_TYPE_CHECKING:
                    pre_toast_text.setText("识别中");
                    break;
                case Const.ACTION_TYPE_CAMERA_TOO_CLOSE:
                    pre_toast_text.setText("请离镜头远一点");
                    break;
                case Const.ACTION_TYPE_CAMERA_TOO_FAR:
                    pre_toast_text.setText("请离镜头近一点");
                    break;
                case Const.ACTION_TYPE_IMAGE_TOO_BLURRED:
                    pre_toast_text.setText("请正对镜头,减少晃动");
                    break;
            }
        });
    }

    //成功
    private void onSuccess(Bitmap bitmap){
        Log.e("onSuccess","bitmap");
        pay_hintRl.setVisibility(View.VISIBLE);
        detect_reg_image_item.setImageBitmap(bitmap);
        finance_by_living_detection.setVisibility(View.VISIBLE);
        finance_quality_test_failed.setVisibility(View.GONE);
    }

    //失败
    private void onFail(String msg){
        pay_hintRl.setVisibility(View.VISIBLE);
        finance_by_living_detection.setVisibility(View.GONE);
        finance_quality_test_failed.setVisibility(View.VISIBLE);
        no_detectTv.setText(msg);
    }
}